#include "Com_h.h"

// {B3172C6E-7413-4543-9A31-A89D2014CE12}
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
        EXTERN_C __declspec(selectany) const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
MIDL_DEFINE_GUID(CLSID, CLSID_TEST, 0xb3172c6e, 0x7413, 0x4543, 0x9a, 0x31, 0xa8, 0x9d, 0x20, 0x14, 0xce, 0x12);

HRESULT GetClassObject(const IID& iid, void** ppvObj, PHANDLE lphProcess)
{
    HRESULT hResult = S_FALSE;
    HANDLE hEvent = CreateEvent(nullptr, TRUE, FALSE, L"ComTest");
    STARTUPINFO si = { 0 };
    si.cb = sizeof(STARTUPINFO);
    PROCESS_INFORMATION pi = { 0 };
    BOOL bRet;
    IStorage* lpIStorage = nullptr;
    IStream* lpIStream = nullptr;

    bRet = CreateProcess(L"..//Bin//COM.exe", nullptr, nullptr, nullptr,
        FALSE, 0, nullptr, nullptr, &si, &pi);
    if (bRet)
    {
        if (lphProcess)
            *lphProcess = pi.hProcess;

        WaitForSingleObject(hEvent, INFINITE);

        hResult = ::StgOpenStorageEx(L"..//Bin//Marshal.bin", STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
            0, 0, nullptr, nullptr, IID_IStorage, (void**)&lpIStorage);
        if (lpIStorage)
        {
            lpIStorage->OpenStream(L"MarshalStream", nullptr, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
                0, &lpIStream);
            if (lpIStream)
            {
                hResult = CoUnmarshalInterface(lpIStream, iid, ppvObj);
                lpIStream->Release();
            }
            lpIStorage->Release();
        }
    }

    return hResult;
}

int main()
{
    HRESULT hResult;
    ITest* lpITest = nullptr;
    HANDLE hProcess = nullptr;

    CoInitialize(nullptr);

    //hResult = CoGetClassObject(CLSID_TEST, CLSCTX_LOCAL_SERVER, nullptr, 
    //    IID_ITest, (void**)&lpITest);
    hResult = GetClassObject(IID_ITest, (void**)&lpITest, &hProcess);
    if (lpITest)
    {
        lpITest->Test();
        lpITest->Release();
    }

    if (hProcess)
        TerminateProcess(hProcess, 0);

    CoUninitialize();

    return 0;
}